package main

import "C"
import (
	"crypto/rand"
	"crypto/rsa"
	"crypto/sha256"
	"crypto/x509"
	"encoding/hex"
	"encoding/json"
	"encoding/pem"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net"
	"os"
	"strconv"
	"strings"
	"sync"
	"time"
)

type node struct {
	//节点ID
	nodeID int
	//节点监听地址
	addr string
	//节点MAC地址
	mac string
	//RSA私钥
	rsaPrivKey []byte
	//RSA公钥
	rsaPubKey []byte
	//证书
	cert *Cert
	//数据锁
	lock sync.Mutex
}

//节点信息
type NodeInfo struct {
	PublicKey []byte
	Addr string
	Mac string
	EndTime int64
}
//证书信息
type Cert struct {
	PublicKey []byte
	Addr string
	Mac string
	EndTime int64
	SignInfo []byte
}

//生成新节点
func NewNode(nodeID int) *node{
	n := new(node)
	ip,_ := n.myIP()
	n.addr = ip + ":" + strconv.Itoa(5000+nodeID)
	n.mac = n.myMac()
	n.nodeID = nodeID
	err := n.GenerateRSAKey()
	if err != nil{
		log.Panic(err)
	}
	n.rsaPubKey = n.getPubKey(nodeID)  //从生成的私钥文件处读取
	n.rsaPrivKey = n.getPivKey(nodeID) //从生成的私钥文件处读取
	n.cert = n.getCert()

	//r := new(Request)
	//r.Timestamp = time.Now().UnixNano()
	//r.ClientAddr = clientAddr
	//r.Operation = oNewNode
	//r.Message.Digest = msgDigest(n.nodeCert())
	//r.Message.Content = strings.TrimSpace(n.nodeCert())
	//br, err := json.Marshal(r)
	//if err != nil {
	//	log.Panic(err)
	//}
	//message := jointMessage(cRequest, br)
	//
	//go tcpDial(message, "127.0.0.1:8000")
	return n
}

func (n *node) nodeJoin(addr string){
	r := new(Request)
	r.Timestamp = time.Now().UnixNano()
	r.ClientAddr = n.addr
	r.Operation = oNewNode
	r.Message.Digest = n.msgDigest(n.nodeCert())
	r.Message.Content = strings.TrimSpace(n.nodeCert())
	br, err := json.Marshal(r)
	if err != nil {
		log.Panic(err)
	}
	message := jointMessage(cRequest, br)

	go tcpDial(message, addr)
}

func (n *node)msgDigest(msg string) string {
	hash := sha256.Sum256([]byte(msg))
	//进行十六进制字符串编码
	return hex.EncodeToString(hash[:])
}

//传入节点编号， 获取对应的公钥
func (n *node) getPubKey(nodeID int) []byte {
	nodeIdString := strconv.Itoa(nodeID)
	key, err := ioutil.ReadFile("Keys/" + nodeIdString +
		"/" + nodeIdString + "_RSA_PUB")
	if err != nil {
		log.Panic(err)
	}
	return key
}

//传入节点编号， 获取对应的私钥
func (n *node) getPivKey(nodeID int) []byte {
	nodeIdString := strconv.Itoa(nodeID)
	key, err := ioutil.ReadFile("Keys/" + nodeIdString +
		"/" + nodeIdString + "_RSA_PIV")
	if err != nil {
		log.Panic(err)
	}
	return key
}

//自签名证书：包括证书信息和自签名
func (n *node) getCert() *Cert{
	//公钥、节点IP地址、节点MAC地址、节点身份信息、证书有效时间
	Cm := new(NodeInfo)
	Cm.PublicKey = n.rsaPubKey
	Cm.Addr = n.addr
	Cm.Mac = n.mac
	Cm.EndTime = time.Now().AddDate(0,1,0).UnixNano()
	//转为字符串
	jsonCm, err := json.Marshal(Cm)
	if err != nil{
		panic(err)
	}
	//制作自签名证书
	digest := sha256.Sum256(jsonCm)
	signInfo := n.RsaSignWithSha256(digest[:], n.rsaPrivKey)
	//返回自签名证书
	Cs := new(Cert)
	Cs.PublicKey = Cm.PublicKey
	Cs.Addr = Cm.Addr
	Cs.Mac = Cm.Mac
	Cs.EndTime = Cm.EndTime
	Cs.SignInfo = signInfo
	return Cs
}

func (n *node) nodeCert()string{
	jsonCs, err := json.Marshal(n.cert)
	if err != nil{
		panic(err)
	}
	cert := string(jsonCs)
	return cert
}

//验证新加入节点的身份
func (n *node) VeriNode(cert string)(ans bool){
	myCert := new(Cert)
	//返回自签名证书和公钥
	err := json.Unmarshal([]byte(cert), myCert)
	if err != nil{
		print(err)
	}

	publicKey := myCert.PublicKey
	Cm := new(NodeInfo)
	Cm.PublicKey = myCert.PublicKey
	Cm.Addr = myCert.Addr
	Cm.Mac = myCert.Mac
	Cm.EndTime = myCert.EndTime
	certInfo, err := json.Marshal(Cm)
	if err != nil{
		panic(err)
	}
	signInfo := myCert.SignInfo
	digest := sha256.Sum256(certInfo)
	ans = n.RsaVerySignWithSha256(digest[:], signInfo, publicKey)
	return
}

//获取mac
func (n *node) myMac()string{
	// 获取本机的MAC地址
	interfaces, err := net.Interfaces()
	if err != nil {
		panic("Poor soul, here is what you got: " + err.Error())
	}
	inter := interfaces[0]
	mac := inter.HardwareAddr.String() //获取本机MAC地址
	return mac
}

func (n *node)myIP()(ip string, err error)  {
	conn, err := net.Dial("udp", "8.8.8.8:53")
	if err != nil {
		fmt.Println(err)
		return
	}
	localAddr := conn.LocalAddr().(*net.UDPAddr)
	fmt.Println(localAddr.String())
	ip = strings.Split(localAddr.String(), ":")[0]
	return
}

func (n *node)GenerateRSAKey() error {
	//1  RSA生成私钥文件步骤
	//--1生成RSA私钥对
	dirStr := "Keys/" + strconv.Itoa(n.nodeID)
	err := os.Mkdir(dirStr,os.ModePerm)
	if err!=nil{
		fmt.Println(err)
	}
	var bits int
	flag.IntVar(&bits,"key flag",1024,"密钥长度,默认值位1024")
	privateKey,err :=rsa.GenerateKey(rand.Reader,bits)
	if err != nil {
		return err
	}
	//--2.将私钥对象转换为DER编码形式
	priKey := x509.MarshalPKCS1PrivateKey(privateKey)
	//--3.创建私钥pem文件
	nodeIdString := strconv.Itoa(n.nodeID)
	file,err := os.Create(dirStr + "/" + nodeIdString + "_RSA_PIV")
	if err != nil {
		return err
	}
	//--4.对私钥信息进行编码，写入到私钥文件中
	block := &pem.Block{
		Type:  "RSA PRIVATE KEY",
		Bytes: priKey,
	}
	err = pem.Encode(file,block)
	if err != nil {
		return  err
	}
	//2 RSA生成公钥文件的核心步骤
	//--1.生成公钥对象
	publicKey := &privateKey.PublicKey
	//--2.将公钥对象转换为DER编码形式
	pubKey,err := x509.MarshalPKIXPublicKey(publicKey)
	if err != nil {
		return  err
	}
	//--3.创建公钥pem文件
	file,err = os.Create(dirStr + "/" + nodeIdString + "_RSA_PUB")
	if err != nil {
		return  err
	}
	//--4.对公钥信息进行编码，写入公钥文件中
	block = &pem.Block{
		Type:  "PUBLIC KEY",
		Bytes: pubKey,
	}
	err = pem.Encode(file,block)
	if err != nil {
		return  err
	}
	return nil
}
